package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.zmj.sy.mom.srv.aps.bean.bo.*;
import com.zmj.sy.mom.srv.aps.bean.dto.mes.*;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.entity.third.HexagonPackagePush;
import com.zmj.sy.mom.srv.aps.bean.entity.third.SinoCamPushPlan;
import com.zmj.sy.mom.srv.aps.bean.vo.aps.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseListResVo;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.feign.ApsMesFeign;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.service.scheduler.inverted.InvertedScheduleContext;
import com.zmj.sy.mom.srv.aps.service.scheduler.inverted.InvertedScheduler;
import com.zmj.sy.mom.srv.aps.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@RequiredArgsConstructor
@Service
public class ApsService {

    private final ApsBatchMapper apsBatchMapper;

    private final OrderMapper orderMapper;

    private final StringRedisTemplate stringRedisTemplate;
    private final ApsOrderMapper apsOrderMapper;
    private final ApsWorkOrderMapper apsWorkOrderMapper;
    private final ApsWorkDetailMapper apsWorkDetailMapper;
    private final ApsDetailWeekdayMapper apsDetailWeekdayMapper;
    private final ProjectConfig projectConig;
    private final CustomerMapper customerMapper;
    private final OrderPhaseMapper orderPhaseMapper;
    private final GroupMapper groupMapper;
//    private final StationGroupMapper stationGroupMapper;
    private final StationMapper stationMapper;
    private final StationWeekdaySchemeMapper stationWeekdaySchemeMapper;
    private final StationWeekdayRuleMapper stationWeekdayRuleMapper;
    private final ShiftTypeMapper shiftTypeMapper;
    private final ShiftMapper shiftMapper;
    private final BreakPeriodMapper breakPeriodMapper;
    private final ApsSchedulingStrategy apsSchedulingStrategy;
    private final OrderBomMapper orderBomMapper;
    private final ReverseDetailMapper reverseDetailMapper;
    private final ImportErpMappingMapper importErpMappingMapper;
    private final HexagonPackagePushMapper hexagonPackagePushMapper;
    private final RestTemplate restTemplate;
    private final ApsMesFeign apsMesFeign;
    private final SinoCamService sinoCamService;
    private final SinoCamPushPlanMapper sinoCamPushPlanMapper;
    private final WeekdaySchemeMapper weekdaySchemeMapper;
    private final WeekdayRuleMapper weekdayRuleMapper;
    private final InvertedScheduler invertedScheduler;

    @Value("${project.feign.mes-url-order}")
    private String mesUrlOrder;


    @Transactional(rollbackFor = Exception.class)
    public void monthSchedule(ApsMonthScheduleReqVo reqVo) {
        InvertedScheduleContext context = InvertedScheduleContext.monthSchedule(reqVo.getFirstBatchDeliveryTime());
        invertedScheduler.schedule(context, reqVo.getOrderIdList());
    }
    @Transactional(rollbackFor = Exception.class)
    public void scheduling(ApsSchedulingBatchReqVo reqVo) {
        log.info("scheduling reqVo: {}", reqVo.getSchedulingRule());

        ApsSchedulingOrderCacheBo orderCache = new ApsSchedulingOrderCacheBo();
        orderCache.setStartDateTime(LocalDateTime.of(LocalDate.now().plusDays(1), LocalTime.of(0, 0, 0)));

        // 取出待排产的订单
        List<Order> orderList = orderMapper.selectBatchIds(reqVo.getOrderIdList());

        // 如果有排产中的订单，则提示报错
        long count = orderList.stream().filter(e -> e.getOrderStatus().equals(4)).count();
        if (count > 0) {
            throw SyExceptionUtils.e("有排产中的订单，请稍后再试");
        }

        // 取出所有待排产的订单
        if (CollUtil.isEmpty(orderList)) {
            throw SyExceptionUtils.e("没有待排产的订单");
        }

        // 检查redis是否有锁定状态，如果有则提示，并且不排产
        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
        String lockFlag = valOperation.get(ApsConstant.APS_SCHEDULING_LOCK);
        if (StringUtils.hasText(lockFlag)) {
            throw SyExceptionUtils.e("{} 等订单排产中!", lockFlag);
        }

        orderCache.setOrderList(orderList);
        orderCache.setSchedulingRule(reqVo.getSchedulingRule());

        List<Integer> orderIds = orderList.stream().map(BaseEntity::getId).collect(Collectors.toList());

        // 取aps
        List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery()
                .in(ApsOrder::getOrderId, orderIds)
                .list();
        orderCache.setApsOrderList(apsOrderList);

        // 1.准备批次数据
        ApsBatch apsBatch = null;
        if (apsBatch == null) {
            apsBatch = genBatch(reqVo);
            apsBatchMapper.insert(apsBatch);
        } else {
            modifyBatch(apsBatch, reqVo);
            apsBatchMapper.updateById(apsBatch);
        }
        orderCache.setApsBatch(apsBatch);

        // 3.把待排产的订单号放入redis，设置锁定状态
        String redisVal = orderCache.getOrderList().stream().map(e -> e.getConstructNo() + "_" + e.getMaterName()).collect(Collectors.joining(","));
        valOperation.set(ApsConstant.APS_SCHEDULING_LOCK, redisVal, 1, TimeUnit.DAYS);

        List<Integer> apsOrderIds = orderCache.getApsOrderList().stream().map(BaseEntity::getId).collect(Collectors.toList());
        apsOrderMapper.lambdaUpdate()
                .set(ApsOrder::getOrderStatus, 4)
                .in(ApsOrder::getId, apsOrderIds)
                .update();

        // 转换MAP属于多此一举
        Map<Integer, List<ApsOrder>> orderMap = apsOrderList.stream().collect(Collectors.groupingBy(ApsOrder::getOrderId));
        for (Map.Entry<Integer, List<ApsOrder>> entry : orderMap.entrySet()) {
            LambdaUpdateWrapper<ApsOrder> wr = Wrappers.lambdaUpdate();
            wr.set(ApsOrder::getPlanStartDateTime, null);
            wr.set(ApsOrder::getPlanEndDateTime, null);
            wr.in(ApsOrder::getId, entry.getValue().stream().map(BaseEntity::getId).collect(Collectors.toList()));
            apsOrderMapper.update(null, wr);
            apsWorkOrderMapper.deleteOrderId(entry.getKey());
            apsWorkDetailMapper.deleteOrderId(entry.getKey());
            apsDetailWeekdayMapper.deleteOrderId(entry.getKey());
        }

        ApsSchedulingFactoryCacheBo factoryCache = new ApsSchedulingFactoryCacheBo();
        factoryCache.setAssemblyStartDateTime(reqVo.getAssemblyStartDateTime());

        initFactoryCache(factoryCache, orderCache);

        // 给所有的排产
        LocalDateTime now = LocalDateTime.now();
        orderCache.getApsBatch().setStatus(1);
        orderCache.getApsBatch().setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        orderCache.getApsBatch().setSchedulingDateTime(now);
        apsBatchMapper.updateById(apsBatch);

        for (Order order : orderCache.getOrderList()) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
            order.setBatchId(apsBatch.getId());
            orderMapper.updateById(order);
        }

        initOrderCache(orderCache, factoryCache);

        scheduleTask(orderCache, factoryCache);

        scheduleWl(orderCache, factoryCache);

        saveAndUpate(orderCache);

        apsBatchMapper.lambdaUpdate().eq(ApsBatch::getStatus, 1).set(ApsBatch::getStatus, 2).update();


//        throw SyExceptionUtils.e("排产故意错误");
        // 排产
//        apsSchedulingStrategy.scheduling(orderCache, apsFactoryCache);





//        List<Order> orderList = orderMapper.lambdaQuery()
//                .in(Order::getOrderStatus, 3, 5)
//                .in(Order::getOrderType, 1, 3, 4)
//                .list();
//
//        for (Order order : orderList) {
//            order.setBatchId(apsBatch.getId());
//        }
//        ApsSchedulingOrderCacheBo orderCache = new ApsSchedulingOrderCacheBo();
//        orderCache.setApsBatch(apsBatch);
//        orderCache.setSchedulingRule(reqVo.getSchedulingRule());
//        orderCache.setAllOrder(orderList);
//
//        // 2.1 排产校验
//        // 2.1 检查redis是否有锁定状态，如果有则提示，并且不排产
//        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
//        String lockFlag = valOperation.get(ApsConstant.APS_SCHEDULING_LOCK);
//        if (StringUtils.hasText(lockFlag)) {
//            throw SyExceptionUtils.e("{} 等订单排产中!", lockFlag);
//        }
//
//        // 3 排产准备
//        // 3.1 锁定排产
//        String redisVal = orderCache.getAllOrder().stream().map(e -> e.getConstructNo() + "_" + e.getMaterName()).collect(Collectors.joining(", "));
//        valOperation.set(ApsConstant.APS_SCHEDULING_LOCK, redisVal, 1, TimeUnit.DAYS);
//
//        Integer i = apsOrderMapper.selectCount(Wrappers.<ApsOrder>lambdaQuery()
//                .in(ApsOrder::getOrderId, orderList.stream().map(BaseEntity::getId).collect(Collectors.toList()))
//                .eq(ApsOrder::getOrderStatus, 4)
//        );
//        if(i > 0){
//            throw SyExceptionUtils.e("已有正在排产的订单，请稍后再试");
//        }
//
//        apsOrderMapper.update(null, Wrappers.<ApsOrder>lambdaUpdate()
//                .set(ApsOrder::getOrderStatus, 4)
//                .in(ApsOrder::getOrderId, orderList.stream().map(BaseEntity::getId).collect(Collectors.toList()))
//        );
//
//        // 3.2 清理信息
//        for (Order order : orderCache.getAllOrder()) {
//
//            // 重置子订单的排产时间
//            apsOrderMapper.lambdaUpdate()
//                    .set(ApsOrder::getPlanStartDateTime, null)
//                    .set(ApsOrder::getPlanEndDateTime, null)
//                    .in(ApsOrder::getOrderId, order.getId())
//                    .update();
//
//            // 删除工单
//            apsWorkOrderMapper.deleteOrderId(order.getId());
//
//            // 删除工单详情
//            apsWorkDetailMapper.deleteOrderId(order.getId());
//
//            // 删除详情日历
//            apsDetailWeekdayMapper.deleteOrderId(order.getId());
//        }
//
//        // 3.3 构建工厂缓存
//        ApsSchedulingFactoryCacheBo factoryCache = new ApsSchedulingFactoryCacheBo();
//
//        // 3.4 设置工厂信息
//        factoryCache.setFactoryCode(projectConig.getFactoryCode());
//
//        // 3.5 设置客户信息
//        List<Integer> customerList = orderCache.getAllOrder().stream().map(Order::getCustomerId).distinct().collect(Collectors.toList());
//        if(CollUtil.isNotEmpty(customerList)){
//            List<Customer> customers = customerMapper.selectBatchIds(customerList);
//            factoryCache.setCustomers(customers);
//        }
//
//        // 3.6 工作组信息
//        List<String> groupNumberString = orderPhaseMapper.selectGroupList(Wrappers.<OrderPhase>query()
//                .in("order_id", orderCache.getAllOrder().stream().map(BaseEntity::getId).collect(Collectors.toList()))
//        );
//        List<Group> groups = groupMapper.lambdaQuery().in(Group::getMyCode, groupNumberString).list();
//        factoryCache.setGroups(groups);
//
//        // 3.6 工作组信息
//        List<StationGroup> stationGroups = stationGroupMapper.selectList(Wrappers.<StationGroup>lambdaQuery().in(StationGroup::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())));
//        factoryCache.setStationGroups(stationGroups);
//
//        // 工位信息
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getStationId).distinct().collect(Collectors.toList());
//        List<Station> stations = stationMapper.selectBatchIds(stationIds);
//        for (Station station : stations) {
//            if(station.getEnterTime() == null || station.getEnterTime() < 0){
//                station.setEnterTime(0);
//            }
//
//            if(station.getOutTime() == null || station.getOutTime() < 0){
//                station.setOutTime(0);
//            }
//
//            if(station.getChangTime() == null || station.getChangTime() < 0){
//                station.setChangTime(0);
//            }
//        }
//        factoryCache.setStations(stations);
//
//        // 快捷从工作组找到主工位列表
//        Map<Integer, List<StationGroup>> stationGroupMap = stationGroups.stream().filter(e -> e.getDefaultGroup().equals(1)).collect(Collectors.groupingBy(StationGroup::getGroupId));
//        Map<Integer, Station> stationMap = stations.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
//        Map<String, List<Station>> masterStationMap = new HashMap<>();
//        for (Group group : groups) {
//
//            List<StationGroup> stationGroups1 = stationGroupMap.get(group.getId());
//            if(CollUtil.isEmpty(stationGroups1)){
//                continue;
//            }
//
//            List<Station> value = stationGroupMap.get(group.getId())
//                    .stream()
//                    .map(e -> stationMap.get(e.getStationId()))
//                    .collect(Collectors.toList());
//
//
//            masterStationMap.put(group.getMyCode(), value);
//        }
//
//        factoryCache.setMasterStationMap(masterStationMap);
//
//        // 工位日历
//        List<StationWeekdayScheme> stationWeekdaySchemes = stationWeekdaySchemeMapper.selectList(Wrappers.<StationWeekdayScheme>lambdaQuery().in(StationWeekdayScheme::getStationId, stationIds));
//        List<StationWeekdayRule> stationWeekdayRules = stationWeekdayRuleMapper.selectList(Wrappers.<StationWeekdayRule>lambdaQuery().in(StationWeekdayRule::getStationId, stationIds));
//        List<Integer> shiftTypeIds = stationWeekdaySchemes.stream().map(StationWeekdayScheme::getShiftTypeId).distinct().collect(Collectors.toList());
//        List<ShiftType> shiftTypes = shiftTypeMapper.selectBatchIds(shiftTypeIds);
//        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().in(Shift::getShiftTypeId, shiftTypeIds));
//        List<BreakPeriod> breakPeriods = breakPeriodMapper.selectList(Wrappers.<BreakPeriod>lambdaQuery().in(BreakPeriod::getShiftId, shifts.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList())));
//
//        factoryCache.setStationWeekdaySchemes(stationWeekdaySchemes);
//        factoryCache.setStationWeekdayRules(stationWeekdayRules);
//        factoryCache.setShiftTypes(shiftTypes);
//        factoryCache.setShifts(shifts);
//        factoryCache.setBreakPeriods(breakPeriods);

        // 4 排产
        // 4.1 排产算法


    }

    public void initFactoryCache(ApsSchedulingFactoryCacheBo factoryCache, ApsSchedulingOrderCacheBo orderCache) {
        // 设置工厂信息
        factoryCache.setFactoryCode(projectConig.getFactoryCode());

        // 设置客户信息
        List<Integer> customerList = orderCache.getApsOrderList().stream().map(ApsOrder::getCustomerId).distinct().collect(Collectors.toList());
        if(CollUtil.isNotEmpty(customerList)){
            List<Customer> customers = customerMapper.selectBatchIds(customerList);
            factoryCache.setCustomers(customers);
        }

        // 工作组信息
        List<String> groupNumberString = orderPhaseMapper.selectGroupList(Wrappers.<OrderPhase>query()
                .in("order_id", orderCache.getOrderList().stream().map(BaseEntity::getId).collect(Collectors.toList()))
        );
        List<Group> groups = groupMapper.lambdaQuery().in(Group::getMyCode, groupNumberString).list();
        factoryCache.setGroups(groups);

        // 工作组工位关联
//        List<StationGroup> stationGroups = stationGroupMapper.selectList(Wrappers.<StationGroup>lambdaQuery().in(StationGroup::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())));
//        factoryCache.setStationGroups(stationGroups);

        // 工位信息
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getStationId).distinct().collect(Collectors.toList());
//        List<Station> stations = stationMapper.selectBatchIds(stationIds);
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())).list();
        List<Integer> stationIds = stations.stream().map(Station::getId).collect(Collectors.toList());

        for (Station station : stations) {
            if(station.getEnterTime() == null || station.getEnterTime() < 0){
                station.setEnterTime(0);
            }

            if(station.getOutTime() == null || station.getOutTime() < 0){
                station.setOutTime(0);
            }

            if(station.getChangTime() == null || station.getChangTime() < 0){
                station.setChangTime(0);
            }
        }

        factoryCache.setStations(stations);

        // 快捷从工作组找到主工位列表
//        Map<Integer, List<StationGroup>> stationGroupMap = stationGroups.stream().filter(e -> e.getDefaultGroup().equals(1)).collect(Collectors.groupingBy(StationGroup::getGroupId));
        Map<Integer, Station> stationMap = stations.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        Map<Integer, List<Station>> stationGroupIdMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId));
        Map<String, List<Station>> masterStationMap = new HashMap<>();
        for (Group group : groups) {

//            List<StationGroup> stationGroups1 = stationGroupMap.get(group.getId());
//            if(CollUtil.isEmpty(stationGroups1)){
//                continue;
//            }

//            List<Station> value = stationGroupMap.get(group.getId())
//                    .stream()
//                    .map(e -> stationMap.get(e.getStationId()))
//                    .collect(Collectors.toList());
            List<Station> value = stationGroupIdMap.get(group.getId());

            masterStationMap.put(group.getMyCode(), value);
        }

        factoryCache.setMasterStationMap(masterStationMap);

        // 工位日历
//        List<WeekdayScheme> stationWeekdaySchemes = weekdaySchemeMapper.selectList(Wrappers.<StationWeekdayScheme>lambdaQuery().in(StationWeekdayScheme::getStationId, stationIds));
        List<Integer> shiftTypeIds = stations.stream().map(Station::getShiftTypeId).collect(Collectors.toList());

        List<WeekdayRule> stationWeekdayRules = weekdayRuleMapper.lambdaQuery().in(WeekdayRule::getShiftTypeId, shiftTypeIds).list();
        List<ShiftType> shiftTypes = shiftTypeMapper.selectBatchIds(shiftTypeIds);
        List<Shift> shifts = shiftMapper.lambdaQuery().in(Shift::getShiftTypeId, shiftTypeIds).list();
        List<BreakPeriod> breakPeriods = breakPeriodMapper.lambdaQuery().in(BreakPeriod::getShiftId, shifts.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList())).list();

//        factoryCache.setStationWeekdaySchemes(stationWeekdaySchemes);
        factoryCache.setWeekdayRules(stationWeekdayRules);
        factoryCache.setShiftTypes(shiftTypes);
        factoryCache.setShifts(shifts);
        factoryCache.setBreakPeriods(breakPeriods);

        // 拼装设备时间链
        LocalDate startDate = orderCache.getStartDateTime().toLocalDate();
        int day = 10;
        LocalDate endDate = startDate.plusDays(day);

        if(factoryCache.getAssemblyStartDateTime() != null && endDate.isBefore(factoryCache.getAssemblyStartDateTime().toLocalDate())){
            LocalDate localDate = factoryCache.getAssemblyStartDateTime().toLocalDate().plusDays(10);
            day = (int) startDate.until(localDate, ChronoUnit.DAYS);
            endDate = localDate;
        }

        factoryCache.setMachines(stations.stream().map(ApsMachine::new).collect(Collectors.toList()));
        factoryCache.addDay(startDate, day);

        // 生产工单占位填充
//        LambdaQueryWrapper<ApsDetailWeekday> wrapper = Wrappers.lambdaQuery();
//        wrapper.ge(ApsDetailWeekday::getShiftDay, startDate);
//        wrapper.le(ApsDetailWeekday::getShiftDay, endDate);
//        wrapper.ge(ApsDetailWeekday::getState, 2);
//        wrapper.ne(ApsDetailWeekday::getState, 4);
//        wrapper.in(ApsDetailWeekday::getOrderType, 1, 3, 4);
//        wrapper.in(ApsDetailWeekday::getStationId, stations.stream().map(Station::getId).distinct().collect(Collectors.toList()));
//        wrapper.orderByAsc(ApsDetailWeekday::getPlanStartDateTime);
//        List<ApsDetailWeekday> apsDetailWeekdays = apsDetailWeekdayMapper.selectList(wrapper);
        List<ApsDetailWeekday> apsDetailWeekdays = new ArrayList<>();

        if(CollUtil.isNotEmpty(apsDetailWeekdays)){
            List<Integer> collect1 = apsDetailWeekdays.stream().map(ApsDetailWeekday::getApsWorkDetailId).distinct().collect(Collectors.toList());
            Map<Integer, ApsWorkDetail> detailMap = apsWorkDetailMapper.selectBatchIds(collect1)
                    .stream()
                    .filter(e -> e.getAppendFlag() == null)
                    .collect(Collectors.toMap(ApsWorkDetail::getId, Function.identity()));

            factoryCache.addTasks(apsDetailWeekdays, detailMap);
        }


        Map<String, List<ApsMachine>> groupCodeMachineMap = new HashMap<>();
        Map<Integer, ApsMachine> idApsMachineMap = factoryCache.getMachines().stream().collect(Collectors.toMap(ApsMachine::getId, Function.identity()));

        for (Map.Entry<String, List<Station>> entry : masterStationMap.entrySet()) {
            List<Station> collect = entry.getValue().stream().filter(e -> e.getWorkAbility() == null).collect(Collectors.toList());
            if(CollUtil.isNotEmpty(collect)){
                throw SyExceptionUtils.e("工位{}没有工作能力", entry.getValue().get(0).getName());
            }
            groupCodeMachineMap.put(entry.getKey(), entry.getValue().stream().map(e -> idApsMachineMap.get(e.getId())).collect(Collectors.toList()));
        }

        // 激光切割工作组合并
        /*
        List<String> joinGroup = Arrays.asList("1-2_JGQG_00", "1-3_JGQG_00");
        List<ApsMachine> temp = new ArrayList<>();
        for (String groupCode : joinGroup) {
            // 取出原本工作组的数据加入缓存
            List<ApsMachine> apsMachines = groupCodeMachineMap.get(groupCode);
            if(apsMachines == null){
                continue;
            }
            temp.addAll(apsMachines);
            // 缓存的指针给加工机器，以便多个工作组共享
            groupCodeMachineMap.put(groupCode, temp);
        }
         */


        factoryCache.setGroupCodeMachineMap(groupCodeMachineMap);

        factoryCache.setIgnorePhaseCode(projectConig.getIgnorePhaseCodeList());

        factoryCache.setPzCode(WorkshopProp.PZ_PHASE_CODE);

        factoryCache.setPzSecond(WorkshopProp.PZ_SECOND);
    }

    public void saveAndUpate(ApsSchedulingOrderCacheBo orderCache) {

        // 保存所有的workOrder
        List<ApsWorkOrderTemp> collect = orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() == null).collect(Collectors.toList());
        Map<Integer, ApsWorkOrderTemp> apsWorkOrderTempIdMap = orderCache.getApsWorkOrderTempIdMap();
        Map<Integer, List<ApsWorkOrderTemp>> apsWorkOrderTempPidMap = orderCache.getApsWorkOrderTempPidMap();


        List<ApsWorkOrderTemp> children = new ArrayList<>(collect);
        while (CollUtil.isNotEmpty(children)) {
            List<ApsWorkOrder> saveBatch = children.stream()
                    .map(e -> {
                        if (e.getPid() != null) {
                            e.getApsWorkOrder().setPid(apsWorkOrderTempIdMap.get(e.getPid()).getApsWorkOrder().getId());
                        }
                        return e.getApsWorkOrder();
                    })
                    .collect(Collectors.toList());
            apsWorkOrderMapper.insertBatch(saveBatch, 1000);

            List<ApsWorkOrderTemp> temp = new ArrayList<>();

            for (ApsWorkOrderTemp child : children) {
                List<ApsWorkOrderTemp> apsWorkOrderTemps = apsWorkOrderTempPidMap.get(child.getId());
                if (CollUtil.isNotEmpty(apsWorkOrderTemps)) {
                    temp.addAll(apsWorkOrderTemps);
                }
            }

            children = temp;
        }

        // 保存所有的workDetail
        for (ApsTask task : orderCache.getTaskList()) {
            ApsWorkOrderTemp apsWorkOrderTemp = apsWorkOrderTempIdMap.get(task.getApsWorkOrderId());
            task.getApsWorkDetailTemp().getApsWorkDetail().setApsWorkOrderId(apsWorkOrderTemp.getApsWorkOrder().getId());
            task.getApsWorkDetailTemp().getApsWorkDetail().setApsWorkOrderPid(apsWorkOrderTemp.getApsWorkOrder().getPid());
        }
        List<ApsWorkDetail> apsWorkDetailList = orderCache.getTaskList().stream().map(ApsTask::getApsWorkDetail).collect(Collectors.toList());
        apsWorkDetailMapper.insertBatch(apsWorkDetailList, 2000);


        // 保存所有的apsDetailWeekday
        for (ApsTask task : orderCache.getTaskList()) {
            for (ApsWeekDayWrap apsWeekDayWrap : task.getAll()) {
                apsWeekDayWrap.setApsWorkOrderId(task.getApsWorkDetail().getApsWorkOrderId());
                apsWeekDayWrap.setApsWorkDetailId(task.getApsWorkDetail().getId());
            }
        }
        List<ApsDetailWeekday> apsDetailWeekdayList = orderCache.getTaskList()
                .stream()
                .flatMap(e -> e.getAll().stream().map(machineCalendar-> {
                    ApsDetailWeekday calendar = new ApsDetailWeekday();

                    calendar.setOrderId(e.getApsWorkDetail().getOrderId());
                    calendar.setApsOrderId(e.getApsWorkDetail().getApsOrderId());
                    calendar.setApsBomId(e.getApsWorkDetail().getApsWorkOrderId());
                    calendar.setPhaseId(e.getApsWorkDetail().getPhaseId());
                    calendar.setPhaseCode(e.getApsWorkDetail().getPhaseCode());
                    calendar.setPhaseName(e.getApsWorkDetail().getPhaseName());
                    calendar.setApsWorkOrderId(e.getApsWorkDetail().getApsWorkOrderId());
                    calendar.setApsWorkDetailId(e.getApsWorkDetail().getId());
                    calendar.setGroupId(e.getApsWorkDetail().getGroupId());

                    calendar.setWorkTime(machineCalendar.getSecond());
                    calendar.setPlanStartDateTime(machineCalendar.getStart());
                    calendar.setPlanEndDateTime(machineCalendar.getEnd());
                    calendar.setShiftId(machineCalendar.getShiftId());
                    calendar.setShiftSeq(machineCalendar.getShiftSeq());
                    calendar.setShiftStartDateTime(machineCalendar.getShiftStartDateTime());
                    calendar.setShiftEndDateTime(machineCalendar.getShiftEndDateTime());
                    calendar.setShiftDay(machineCalendar.getShiftDay());
                    calendar.setStationGroupId(e.getApsWorkDetail().getStationGroupId());
                    calendar.setStationId(e.getApsWorkDetail().getStationId());
                    calendar.setState(1); // 3 已排产
                    calendar.setOrderType(orderCache.getOrderIdMap().get(e.getApsWorkOrder().getOrderId()).getOrderType());
                    return calendar;
                }))
                .collect(Collectors.toList());
        apsDetailWeekdayMapper.insertBatch(apsDetailWeekdayList, 2000);

        // 更新 apsOrder
        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
            apsOrder.setOrderStatus(5);
        }
        apsOrderMapper.updateBatchById(orderCache.getApsOrderList(), 500);

        // 更新 order
        for (Order order : orderCache.getOrderList()) {
            order.setOrderStatus(5);
        }
        orderMapper.updateBatchById(orderCache.getOrderList(), 100);
    }

    public void scheduleWl(ApsSchedulingOrderCacheBo orderCache, ApsSchedulingFactoryCacheBo factoryCache) {
        List<ApsWorkOrderTemp> collect = orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getApsWorkOrder().getWorkChain().equals("WL")).collect(Collectors.toList());
        Map<Integer, ApsWorkOrderTemp> apsWorkOrderMap = orderCache.getApsWorkOrderTempList().stream().collect(Collectors.toMap(e -> e.getId(), Function.identity()));
        for (ApsWorkOrderTemp apsWorkOrderTemp : collect) {
            ApsWorkOrderTemp apsWorkOrderTemp1 = apsWorkOrderMap.get(apsWorkOrderTemp.getPid());
            apsWorkOrderTemp.getApsWorkOrder().setPlanStartDateTime(apsWorkOrderTemp1.getApsWorkOrder().getPlanStartDateTime());
            apsWorkOrderTemp.getApsWorkOrder().setPlanEndDateTime(apsWorkOrderTemp1.getApsWorkOrder().getPlanStartDateTime());
        }

    }

    public void scheduleTask(ApsSchedulingOrderCacheBo orderCache, ApsSchedulingFactoryCacheBo factoryCache) {
        String patter = ".*(P[1-6]_170|PDB_170|-0[12]0[23])$";
        String namePattern = ".*([左右]侧护板|挡板组件)$";
        // 取P1到P6的工单


        List<String> assLog = new ArrayList<>();
        List<String> partLog = new ArrayList<>();

        // 取P1到P6的工单
        for (ApsTask e : orderCache.getTaskList()) {
            if (e.getApsWorkDetail().getPlmId().matches(patter) || e.getApsWorkDetail().getMaterName().matches(namePattern) || (e.getApsWorkOrder().getLevel().equals(1) && e.getApsWorkOrder().getWorkChain().equals("WW"))) {
                e.setStatus(2);
            } else {
                e.setStatus(1);
            }
        }
        orderCache.getTaskList().sort((e1, e2) -> {
            int cmp = 0;
            if(orderCache.getSchedulingRule().equals(1)){
                cmp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                if (cmp != 0) {
                    return cmp;
                }
                cmp = e1.getApsWorkOrder().getApsOrderId().compareTo(e2.getApsWorkOrder().getApsOrderId());
                if (cmp != 0) {
                    return cmp;
                }
            } else if(orderCache.getSchedulingRule().equals(2)){
                // 先按月排序
                cmp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getPlannedMonth().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getPlannedMonth());
                if (cmp != 0) {
                    return cmp;
                }

                // 再按月内的订单顺序
                cmp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                if (cmp != 0) {
                    return cmp;
                }

                // 再按包排序
                cmp = e1.getApsWorkOrder().getApsOrderId().compareTo(e2.getApsWorkOrder().getApsOrderId());
                if (cmp != 0) {
                    return cmp;
                }
            } else {
                cmp = e1.getApsWorkOrder().getApsOrderId().compareTo(e2.getApsWorkOrder().getApsOrderId());
                if (cmp != 0) {
                    return cmp;
                }
                cmp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                if (cmp != 0) {
                    return cmp;
                }
            }


            // BOM 层级
            cmp = e1.getApsWorkOrder().getLevel().compareTo(e2.getApsWorkOrder().getLevel());
            if (cmp != 0) {
                return -cmp;
            }
            // BOM的工序
            cmp = e1.getApsWorkDetail().getPhaseSeq().compareTo(e2.getApsWorkDetail().getPhaseSeq());
            return cmp;
        });

        LocalDateTime start = null;
        Map<Integer, Map<Integer, List<ApsTask>>> idPhaseSeqMap = orderCache.getWorkOrderIdPhaseSeqMap();
        for (ApsTask currentTask : orderCache.getTaskList()) {

            if (currentTask.getStatus() != 2 && currentTask.getStatus() != 4 ) {
                continue;
            }

            start = null;
            List<ApsTask> preTask = null;

            Optional<Integer> max = idPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId()).keySet().stream().filter(e -> e < currentTask.getPhaseSeq()).max(Integer::compareTo);
            if (max.isPresent()) {
                preTask = idPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId()).get(max.get());
            }

            if (preTask != null && !preTask.isEmpty()) {
                preTask.stream().filter(task -> task.getPlanEndDateTime() == null).findFirst().ifPresent(task -> {
                    throw SyExceptionUtils.e("[{}]的工序[{}]在工序[{}]之前", currentTask.getApsWorkDetail().getMaterName(), currentTask.getApsWorkDetail().getPhaseCode(), task.getApsWorkDetail().getPhaseCode());
                });

                List<ApsTask> tasks = preTask.stream().filter(e -> e.getConsumerStatus().equals(1) || e.getConsumerStatus().equals(2)).sorted(Comparator.comparing(ApsTask::getConsumerStatus).reversed()).collect(Collectors.toList());
                BigDecimal total = tasks.stream().map(e -> e.getApsWorkDetail().getTotalCount()).reduce(BigDecimal::add).orElseThrow(() -> SyExceptionUtils.e("没有找到前一道工序的数量"));
                if (currentTask.getApsWorkDetail().getTotalCount().compareTo(total) > 0) {
                    throw SyExceptionUtils.e("数量不足");
                }

                BigDecimal remainder = currentTask.getApsWorkDetail().getTotalCount();
                List<ApsTask> newPreTask = new ArrayList<>();
                for (ApsTask task : tasks) {
                    if (remainder.compareTo(BigDecimal.ZERO) <= 0) {
                        break;
                    }
                    BigDecimal count = task.getApsWorkDetail().getTotalCount();
                    newPreTask.add(task);
                    if (remainder.compareTo(count) > 0) {
                        task.setConsumerStatus(3);
                        remainder = remainder.subtract(count);
                    } else if (remainder.compareTo(count) == 0) {
                        task.setConsumerStatus(3);
                        task.setConsumerCount(task.getConsumerCount().add(remainder));
                        break;
                    } else {
                        task.setConsumerStatus(2);
                        task.setConsumerCount(task.getConsumerCount().add(remainder));
                        remainder = BigDecimal.ZERO;
                    }
                    task.setConsumerCount(task.getConsumerCount().add(remainder));
                }

                ApsTask maxPreTask = newPreTask.stream().max(Comparator.comparing(ApsTask::getPlanEndDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到前一道工序的时间"));
                start = maxPreTask.getPlanEndDateTime();
            } else {
                // 1.2 如果没有前一道工序，校验子节点的完成时间
                List<ApsTask> optionalTask = orderCache.getWorkOrderPidMap().get(currentTask.getApsWorkOrderId()).stream().filter(e-> !e.getStatus().equals(1)).collect(Collectors.toList());

                if (CollUtil.isNotEmpty(optionalTask)) {

                    // 判断是否有未完成的子节点，如果有则抛出异常
                    optionalTask.stream().filter(task -> task.getPlanEndDateTime() == null).findFirst().ifPresent(task -> {
                        throw SyExceptionUtils.e("子节点未完成");
                    });

                    // ---- 修复BUG - 开始 ---
                    Map<Integer, List<ApsTask>> childrenNodeMap = optionalTask.stream().collect(Collectors.groupingBy(e->e.getApsWorkOrderTemp().getId()));
                    for (Map.Entry<Integer, List<ApsTask>> entry : childrenNodeMap.entrySet()) {
                        Integer maxPhaseSeq = entry.getValue().stream().map(ApsTask::getPhaseSeq).max(Integer::compare).orElseThrow(() -> SyExceptionUtils.e("没有找到最大工序"));
                        List<ApsTask> maxPhaseSeqList = entry.getValue().stream().filter(e -> e.getApsWorkDetail().getPhaseSeq().equals(maxPhaseSeq)).filter(e -> e.getConsumerStatus().equals(1) || e.getConsumerStatus().equals(2)).sorted(Comparator.comparing(ApsTask::getConsumerStatus).reversed()).collect(Collectors.toList());
                        BigDecimal total = maxPhaseSeqList.stream().map(e -> e.getApsWorkDetail().getTotalCount()).reduce(BigDecimal::add).orElseThrow(() ->
                                SyExceptionUtils.e("没有找到前一道工序的数量")
                        );
                        BigDecimal consumerCount = maxPhaseSeqList.stream().map(ApsTask::getConsumerCount).reduce(BigDecimal::add).orElseThrow(() -> SyExceptionUtils.e("没有找到前一道工序的数量"));
                        BigDecimal parentTotalCount = currentTask.getApsWorkDetail().getTotalCount();
                        BigDecimal partCount = orderCache.getApsWorkOrderTempIdMap().get(maxPhaseSeqList.get(0).getApsWorkOrderId()).getApsWorkOrder().getPartCount();
                        BigDecimal sourceTotal = total.subtract(consumerCount);
                        BigDecimal koujianTotal = parentTotalCount.multiply(partCount);
                        BigDecimal remainder = sourceTotal.subtract(koujianTotal);

//                        System.out.println(String.format("总数量: %s, 已消耗: %s, 父节点数量: %s, 单件数量: %s,需求数: %s, 剩余数: %s", total, consumerCount, parentTotalCount, partCount, koujianTotal, sourceTotal));

                        if (remainder.compareTo(BigDecimal.ZERO) < 0) {
                            throw SyExceptionUtils.e("数量不足");
//                            break;
                        }

                        remainder = koujianTotal;

                        List<ApsTask> newPreTask = new ArrayList<>();
                        for (ApsTask task : maxPhaseSeqList) {
                            BigDecimal count = task.getApsWorkDetail().getTotalCount().subtract(task.getConsumerCount());
                            newPreTask.add(task);
                            if (remainder.compareTo(count) > 0) {
                                task.setConsumerStatus(3);
                                remainder = remainder.subtract(count);
                                task.setConsumerCount(task.getConsumerCount().add(count));
                            } else if (remainder.compareTo(count) == 0) {
                                task.setConsumerStatus(3);
                                remainder = remainder.subtract(count);
                                task.setConsumerCount(task.getConsumerCount().add(count));
                            } else {
                                task.setConsumerStatus(2);
                                task.setConsumerCount(task.getConsumerCount().add(remainder));
                                remainder = BigDecimal.ZERO;
                            }

                            if (remainder.compareTo(BigDecimal.ZERO) == 0) {
                                break;
                            }
                        }

                        // 之后取子节点的最大结束时间作为开始时间
                        ApsTask task = newPreTask.stream().max(Comparator.comparing(ApsTask::getEndTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到最大的子节点时间"));
                        if(start == null || start.isBefore(task.getEndTime())){
                            start = task.getEndTime();
                        }

                    }

                } else {
                    start = orderCache.getStartDateTime();
                }
            }


            // 2.找工序对应的设备列表
            List<ApsMachine> machines = factoryCache.getGroupCodeMachineMap().get(currentTask.getGroupCode());
            if (CollUtil.isEmpty(machines)) {
                throw SyExceptionUtils.e("没有找到工作组:[" + currentTask.getGroupCode() + "], 对应的工序:[" + currentTask.getPhaseCode() + "]");
            }


            // 3.把此工序在该列表中依次排产
            List<ApsDetailWeekdayWrap> l = new ArrayList<>();
            for (ApsMachine machine : machines) {

                if (start == null) {
                    start = orderCache.getStartDateTime();
                }

//                if(currentTask.getPhaseCode().equals(apsFactoryCache.getPzCode())){
//                    start = start.plusSeconds(apsFactoryCache.getPzSecond());
//                }

                if (start.isBefore(factoryCache.getAssemblyStartDateTime())) {
                    start = factoryCache.getAssemblyStartDateTime();
                }

                ApsDetailWeekdayWrap scheduling = ApsTaskUtils.scheduling(factoryCache, orderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper, l);
//                ApsDetailWeekdayWrap scheduling = ApsUtils.scheduling(apsFactoryCache, apsOrderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper);
                l.add(scheduling);
            }

            // 4.取出时间最靠前的一次排产结果
            ApsDetailWeekdayWrap calendarWrap = l.stream().min(Comparator.comparing(ApsDetailWeekdayWrap::getStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("排产异常"));
            currentTask.getApsWorkDetail().setPlanStartDateTime(calendarWrap.getStartDateTime());
            currentTask.getApsWorkDetail().setPlanEndDateTime(calendarWrap.getEndDateTime());
            currentTask.setNextTask(calendarWrap.getNext());
            calendarWrap.getPrevious().setNextTask(currentTask);
            currentTask.getApsWorkDetail().setStationId(calendarWrap.getMachine().getId());
            currentTask.setStartMachineCalendar(calendarWrap.getStartMachineCalendar());
            currentTask.setAll(calendarWrap.getAll());
            currentTask.getApsWorkDetail().setStatus(2);
            currentTask.setStatus(5);

            assLog.add(String.format("包号:%s, 零件名称:%s, PLMID:%s, 工序:%s, 开始时间:%s, 结束时间:%s, 工位:%s, 工作组:%s, 数量:%s, 工位数量:%s",
                    PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
                    currentTask.getApsWorkDetail().getMaterName(),
                    currentTask.getApsWorkDetail().getPlmId(),
                    currentTask.getApsWorkDetail().getPhaseCode(),
                    currentTask.getApsWorkDetail().getPlanStartDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
                    currentTask.getApsWorkDetail().getPlanEndDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
                    currentTask.getApsWorkDetail().getStationId(),
                    currentTask.getApsWorkDetail().getGroupCode(),
                    currentTask.getApsWorkDetail().getTotalCount().intValue(),
                    machines.size()
            ));


//            System.out.println(String.format("包号:%s, 零件名称:%s, PLMID:%s, 工序:%s, 开始时间:%s, 结束时间:%s, 工位:%s, 工作组:%s, 数量:%s, 工位数量:%s",
//                    PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
//                    currentTask.getApsWorkDetail().getMaterName(),
//                    currentTask.getApsWorkDetail().getPlmId(),
//                    currentTask.getApsWorkDetail().getPhaseCode(),
//                    currentTask.getApsWorkDetail().getPlanStartDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
//                    currentTask.getApsWorkDetail().getPlanEndDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
//                    currentTask.getApsWorkDetail().getStationId(),
//                    currentTask.getApsWorkDetail().getGroupCode(),
//                    currentTask.getApsWorkDetail().getTotalCount().intValue(),
//                    machines.size()
//            ));

        }

        // -------- 开始进行零件排产 --------
        for (ApsTask task : orderCache.getTaskList()) {
            if (task.getStatus().equals(1)) {
                task.setStatus(2);
            }
        }

        Map<Integer, Order> orderIdMap = orderCache.getOrderIdMap();
        Map<Integer, ApsOrder> apsOrderIdMap = orderCache.getApsOrderIdMap();
        Map<Integer, Map<Integer, ReverseDetail>> reverseDetailOrderIdPhaseIdMap = orderCache.getReverseDetailOrderIdPhaseIdMap();

        List<ApsTask> collect = orderCache.getTaskList()
                .stream()
                .sorted((e1, e2) -> {

                    int comp = 0;
                    if(orderCache.getSchedulingRule().equals(1)){
                        comp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return - comp;
                        }
                        comp = orderIdMap.get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderIdMap.get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return - comp;
                        }
                    } else {

                        comp = orderCache.getApsOrderIdMap().get(e1.getApsWorkOrder().getApsOrderId()).getSeq().compareTo(orderCache.getApsOrderIdMap().get(e2.getApsWorkOrder().getApsOrderId()).getSeq());
                        if (comp != 0) {
                            return comp;
                        }

                        comp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return comp;
                        }
                    }

                    comp = apsOrderIdMap.get(e1.getApsWorkOrder().getApsOrderId()).getSeq().compareTo(apsOrderIdMap.get(e2.getApsWorkOrder().getApsOrderId()).getSeq());
                    if (comp != 0) {
                        return - comp;
                    }

                    ReverseDetail reverseDetail1 = reverseDetailOrderIdPhaseIdMap.get(e1.getApsWorkOrder().getOrderId()).get(e1.getApsWorkDetail().getPhaseId());
                    ReverseDetail reverseDetail2 = reverseDetailOrderIdPhaseIdMap.get(e2.getApsWorkOrder().getOrderId()).get(e2.getApsWorkDetail().getPhaseId());

                    comp = reverseDetail1.getReverseStartTime().compareTo(reverseDetail2.getReverseStartTime());
                    if (comp != 0) {
                        return - comp;
                    }

                    comp = reverseDetail1.getLevel().compareTo(reverseDetail2.getLevel());
                    if (comp != 0) {
                        return - comp;
                    }

                    if(reverseDetail1.getBomId().compareTo(reverseDetail2.getBomId()) == 0){
                        return - reverseDetail1.getPhaseSeq().compareTo(reverseDetail2.getPhaseSeq());
                    }
                    return - reverseDetail1.getId().compareTo(reverseDetail2.getId());
                })
                .collect(Collectors.toList());


        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = orderCache.getWorkOrderIdPhaseSeqMap();
        Map<Integer, Map<Integer, Queue<LocalDateTime>>> parentLastPhaseStartDateTimeMap = new HashMap<>();
        Map<Integer, Map<Integer, Queue<LocalDateTime>>> nestPhaseStartDateTimeMap = new HashMap<>();

        for (ApsTask currentTask : collect) {

            // 判断是否为最后一道工序，如果是取上级，如果不是取上一道工序
            // 判断父级是否等于当前工序或者小于当前工序，如果小于，则累加到当前数量
            Optional<Integer> firstOpt = workOrderIdPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId())
                    .keySet()
                    .stream()
                    .filter(e -> e > currentTask.getPhaseSeq())
                    .findFirst();

            LocalDateTime endDateTime = null;


            if(currentTask.getStatus().equals(5)) {
                log.info("*包号:{}, 零件名称:{}, PLMID:{}, 工序:{}, 下道工序:{}, 准备时间:{}, 开始时间:{}, 结束时间:{}, 工位:{}, 工作组:{}, 数量:{}",
                        PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
                        currentTask.getApsWorkDetail().getMaterName(),
                        currentTask.getApsWorkDetail().getPlmId(),
                        currentTask.getApsWorkDetail().getPhaseCode(),
                        firstOpt.isPresent()? "有": "无",
                        MkDateTimeUtils.toString(endDateTime),
                        MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanStartDateTime()),
                        MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanEndDateTime()),
                        currentTask.getApsWorkDetail().getStationId(),
                        currentTask.getApsWorkDetail().getGroupCode(),
                        currentTask.getApsWorkDetail().getTotalCount().intValue()
                );

                continue;
            }

            if (!firstOpt.isPresent() && currentTask.getApsWorkOrder().getLevel() > 1) {
                if(parentLastPhaseStartDateTimeMap.getOrDefault(currentTask.getApsWorkOrder().getApsOrderId(), new HashMap<>()).get(currentTask.getApsWorkDetail().getPhaseId()) == null){
                    List<ApsTask> collect1 = collect.stream().filter(e -> e.getApsWorkOrderTemp().getId().equals(currentTask.getApsWorkOrderTemp().getPid())).collect(Collectors.toList());
                    Map<Integer, List<ApsTask>> collect2 = collect1.stream().collect(Collectors.groupingBy(ApsTask::getPhaseSeq));
                    int min = Collections.min(collect2.keySet());
                    List<ApsTask> taskList = collect2.get(min);
                    List<ApsTask> collect3 = taskList.stream().sorted(Comparator.comparing((ApsTask e)->e.getApsWorkDetail().getPlanStartDateTime()).reversed()).collect(Collectors.toList());
                    BigDecimal partCount = currentTask.getApsWorkOrder().getPartCount();
                    for (ApsTask localDateTime : collect3) {
                        int count = partCount.intValue() * localDateTime.getApsWorkDetail().getTotalCount().intValue();
                        for (int i = 0; i < count; i++) {
                            parentLastPhaseStartDateTimeMap.computeIfAbsent(currentTask.getApsWorkOrder().getApsOrderId(), e -> new HashMap<>())
                                    .computeIfAbsent(currentTask.getApsWorkDetail().getPhaseId(), e -> new ArrayDeque<>())
                                    .add(localDateTime.getApsWorkDetail().getPlanStartDateTime());
                        }
                    }
                }

                int ct = currentTask.getApsWorkDetail().getTotalCount().intValue();
                Queue<LocalDateTime> queue = parentLastPhaseStartDateTimeMap.get(currentTask.getApsWorkOrder().getApsOrderId()).get(currentTask.getApsWorkDetail().getPhaseId());

                for (int i = 0; i < ct; i++) {
                    endDateTime = queue.poll();
                }
                // 零件提前配盘的时间
                endDateTime = endDateTime.minusHours(8);

            } else if(currentTask.getApsWorkOrder().getLevel().equals(1)){
//                continue;
            } else {
                Queue<LocalDateTime> queue = nestPhaseStartDateTimeMap.computeIfAbsent(currentTask.getApsWorkOrder().getApsOrderId(), e->new HashMap<>()).get(currentTask.getApsWorkDetail().getPhaseId());
                if(queue == null){
                    List<ApsTask> taskList = workOrderIdPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId()).get(firstOpt.get());
                    List<LocalDateTime> collect1 = taskList.stream().flatMap(e -> Stream.generate(() -> e.getApsWorkDetail().getPlanStartDateTime()).limit(e.getApsWorkDetail().getTotalCount().intValue())).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
                    queue = new ArrayDeque<>(collect1.size());
                    queue.addAll(collect1);
                }
                int ct = currentTask.getApsWorkDetail().getTotalCount().intValue();
                for (int i = 0; i < ct; i++) {
                    endDateTime = queue.poll();
                }
            }

//            if (!firstOpt.isPresent() && currentTask.getApsWorkOrder().getLevel() > 1) {
//                break;
//            }


            // 2.找工序对应的设备列表
            List<ApsMachine> machines = factoryCache.getGroupCodeMachineMap().get(currentTask.getGroupCode());
            if (CollUtil.isEmpty(machines)) {
                throw SyExceptionUtils.e("没有找到工作组:[" + currentTask.getGroupCode() + "], 对应的工序:[" + currentTask.getPhaseCode() + "]");
            }

            // 3.把此工序在该列表中依次排产
            List<ApsDetailWeekdayWrap> l = new ArrayList<>();
            for (ApsMachine machine : machines) {
//                ApsDetailWeekdayWrap scheduling = Aps2Utils.schedulingBottleneck(factoryCache, orderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper);
                ApsDetailWeekdayWrap scheduling = ApsTaskUtils.schedulingBottleneckWuxian(factoryCache, orderCache, endDateTime, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper);
                l.add(scheduling);
            }

            // 4.取出时间最靠后的一次排产结果
            ApsDetailWeekdayWrap calendarWrap = l.stream().filter(e-> e.getStartDateTime() != null && e.getEndDateTime() != null).max(Comparator.comparing(ApsDetailWeekdayWrap::getStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("排产异常"));

            currentTask.getApsWorkDetail().setPlanStartDateTime(calendarWrap.getStartDateTime());
            currentTask.getApsWorkDetail().setPlanEndDateTime(calendarWrap.getEndDateTime());
            currentTask.setNextTask(calendarWrap.getNext());
            calendarWrap.getPrevious().setNextTask(currentTask);
            currentTask.getApsWorkDetail().setStationId(calendarWrap.getMachine().getId());
            currentTask.setStartMachineCalendar(calendarWrap.getStartMachineCalendar());
            currentTask.setAll(calendarWrap.getAll());
            currentTask.getApsWorkDetail().setStatus(2);
            currentTask.setAppendFlag(2);
            currentTask.getApsWorkDetail().setAppendFlag(2);
            currentTask.getApsWorkOrder().setAppendFlag(2);

//            DiffTime diffTime = diffTimeIdMap.get(currentTask.getApsWorkDetail().getId());
//            diffTime.setTargetPlanStartDateTime(calendarWrap.getStartDateTime());
//            diffTime.setTargetPlanEndDateTime(calendarWrap.getEndDateTime());
//            diffTime.setTargetStationId(calendarWrap.getMachine().getId());
//            System.out.println(diffTime);



//            if(currentTask.getApsWorkOrder().getLevel() > 2){
//                continue;
//            }

            partLog.add(String.format("包号:%s, 零件名称:%s, PLMID:%s, 工序:%s, 下道工序:%s, 开始时间:%s, 结束时间:%s, 工位:%s, 工作组:%s, 数量:%s",
                    PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
                    currentTask.getApsWorkDetail().getMaterName(),
                    currentTask.getApsWorkDetail().getPlmId(),
                    currentTask.getApsWorkDetail().getPhaseCode(),
                    firstOpt.isPresent()? "有": "无",
                    MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanStartDateTime()),
                    MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanEndDateTime()),
                    currentTask.getApsWorkDetail().getStationId(),
                    currentTask.getApsWorkDetail().getGroupCode(),
                    currentTask.getApsWorkDetail().getTotalCount().intValue()));
        }


        // 先给各项赋值时间
        List<ApsWorkDetailTemp> workDetailTempList = orderCache.getTaskList().stream().map(ApsTask::getApsWorkDetailTemp).collect(Collectors.toList());
        for (ApsWorkDetailTemp e : workDetailTempList) {
            if (e.getApsWorkOrder().getPlanStartDateTime() == null || e.getApsWorkDetail().getPlanStartDateTime().isBefore(e.getApsWorkOrder().getPlanStartDateTime())) {
                e.getApsWorkOrder().setPlanStartDateTime(e.getApsWorkDetail().getPlanStartDateTime());
            }

            if (e.getApsWorkOrder().getPlanEndDateTime() == null || e.getApsWorkDetail().getPlanEndDateTime().isAfter(e.getApsWorkOrder().getPlanEndDateTime())) {
                e.getApsWorkOrder().setPlanEndDateTime(e.getApsWorkDetail().getPlanEndDateTime());
            }

            ApsOrder apsOrder = apsOrderIdMap.get(e.getApsWorkOrder().getApsOrderId());
            if(apsOrder.getPlanStartDateTime() == null || e.getApsWorkDetail().getPlanStartDateTime().isBefore(apsOrder.getPlanStartDateTime())){
                apsOrder.setPlanStartDateTime(e.getApsWorkDetail().getPlanStartDateTime());
                if(e.getApsWorkDetail().getPlanStartDateTime().isBefore(factoryCache.getAssemblyStartDateTime())){
                    apsOrder.setPlanStartDateTime(factoryCache.getAssemblyStartDateTime());
                }
            }
            if(apsOrder.getPlanEndDateTime() == null || e.getApsWorkDetail().getPlanEndDateTime().isAfter(apsOrder.getPlanEndDateTime())){
                apsOrder.setPlanEndDateTime(e.getApsWorkDetail().getPlanEndDateTime());
            }

            Order order = orderIdMap.get(e.getApsWorkOrder().getOrderId());
            if(order.getPlanStartDateTime() == null || apsOrder.getPlanStartDateTime().isBefore(order.getPlanStartDateTime())){
                order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                if(e.getApsWorkDetail().getPlanStartDateTime().isBefore(factoryCache.getAssemblyStartDateTime())){
                    order.setPlanStartDateTime(factoryCache.getAssemblyStartDateTime());
                }
            }
            if(order.getPlanEndDateTime() == null || apsOrder.getPlanEndDateTime().isAfter(order.getPlanEndDateTime())){
                order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
            }
        }

        try {
            FileUtils.writeLines(new File("/home/apslog/assLog.txt"), assLog);
            FileUtils.writeLines(new File("/home/apslog/partLog.txt"), partLog);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public void initOrderCache(ApsSchedulingOrderCacheBo orderCache, ApsSchedulingFactoryCacheBo factoryCache) {

        // 根据已有的 orderList 初始化 Order 的 Map
        Map<Integer, Order> orderIdMap = orderCache.getOrderList().stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        orderCache.setOrderIdMap(orderIdMap);

        // 根据已有的 apsOrderList 初始化 ApsOrder 的 Map
        Map<Integer, List<ApsOrder>> apsOrderOrderIdMap = orderCache.getApsOrderList().stream().collect(Collectors.groupingBy(ApsOrder::getOrderId));
        orderCache.setApsOrderOrderIdMap(apsOrderOrderIdMap);

        Map<Integer, ApsOrder> apsOrderIdMap = orderCache.getApsOrderList().stream().collect(Collectors.toMap(ApsOrder::getId, Function.identity()));
        orderCache.setApsOrderIdMap(apsOrderIdMap);

        // 初始化所有订单 BOM 的 List 和 Map
        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().in(OrderBom::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        orderCache.setOrderBomList(orderBomList);

        Map<Integer,List<OrderBom>> orderBomOrderIdMap = orderBomList.stream().collect(Collectors.groupingBy(OrderBom::getOrderId));
        orderCache.setOrderBomOrderIdMap(orderBomOrderIdMap);

        Map<Integer,OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        orderCache.setOrderBomIdMap(orderBomIdMap);

        // 初始化所有订单 PHASE 的 List 和 Map
        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().in(OrderPhase::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        orderCache.setOrderPhaseList(orderPhaseList);

        Map<Integer,List<OrderPhase>> orderPhaseOrderIdMap = orderPhaseList.stream().collect(Collectors.groupingBy(OrderPhase::getOrderId));
        orderCache.setOrderPhaseOrderIdMap(orderPhaseOrderIdMap);

        Map<Integer,OrderPhase> orderPhaseIdMap = orderPhaseList.stream().collect(Collectors.toMap(OrderPhase::getId, Function.identity()));
        orderCache.setOrderPhaseIdMap(orderPhaseIdMap);

        // 初始化所有包的 ApsWorkOrder
        List<ApsWorkOrder> apsWorkOrderList = orderCache.getOrderBomList()
                .stream()
                .map(e -> {
                    ApsWorkOrder apsBom = MkBeanUtils.copyProperties(e, ApsWorkOrder.class);
                    apsBom.setBomId(e.getId());
                    apsBom.setBomPid(e.getPid());
                    apsBom.setId(null);
                    apsBom.setPid(null);
                    apsBom.setStatus(1);
                    apsBom.setFinishCount(new BigDecimal(0));
                    apsBom.setTotalCount(e.getTotalCount());
                    apsBom.setOrderType(orderCache.getOrderIdMap().get(e.getOrderId()).getOrderType());
                    apsBom.setPlmId(e.getPlmId());
//                    apsBom.setApsOrderId(apsOrder.getId());
//                    apsBom.setOrderCount(e.getTotalCount().multiply(new BigDecimal(apsOrder.getOrderQty())));
                    return apsBom;
                })
                .flatMap(e ->
                    apsOrderOrderIdMap.get(e.getOrderId())
                    .stream()
                    .map(e1 -> {
                        ApsWorkOrder awo = new ApsWorkOrder();
                        BeanUtils.copyProperties(e, awo);
                        awo.setApsOrderId(e1.getId());
                        awo.setOrderCount(e.getTotalCount().multiply(new BigDecimal(e1.getOrderQty())));
                        return awo;
                    })
                )
//                .filter(e -> !(e.getErpCode().startsWith("010") || e.getErpCode().startsWith("020") || e.getErpCode().startsWith("050")))
                .collect(Collectors.toList());

        // 构建 ApsWorkOrder 缓存对象
        List<ApsWorkOrderTemp> apsWorkOrderTempList = apsWorkOrderList.stream()
                .map(e -> {
                    ApsWorkOrderTemp apsWorkOrderTemp = new ApsWorkOrderTemp();
                    apsWorkOrderTemp.setApsWorkOrder(e);
                    return apsWorkOrderTemp;
                })
                .collect(Collectors.toList());

        Map<Integer, Map<Integer, List<ApsWorkOrderTemp>>> pidBomMap = apsWorkOrderTempList.stream()
                .filter(e->e.getApsWorkOrder().getBomPid() != null)
                .collect(Collectors.groupingBy(e-> e.getApsWorkOrder().getApsOrderId(), Collectors.groupingBy(e-> e.getApsWorkOrder().getBomPid())));
        List<ApsWorkOrderTemp> parentBoms = apsWorkOrderTempList.stream().filter(e -> e.getApsWorkOrder().getBomPid() == null).collect(Collectors.toList());
        int workOrderId = 1;
        if(CollUtil.isNotEmpty(parentBoms)){
            for (ApsWorkOrderTemp parentBom : parentBoms) {
                parentBom.setId(workOrderId++);
            }
        }
        while (CollUtil.isNotEmpty(parentBoms)) {

            List<ApsWorkOrderTemp> temp = new ArrayList<>();
            for (ApsWorkOrderTemp parentBom : parentBoms) {
                List<ApsWorkOrderTemp> apsBomChildren = pidBomMap.get(parentBom.getApsWorkOrder().getApsOrderId()).get(parentBom.getApsWorkOrder().getBomId());
                if (CollUtil.isEmpty(apsBomChildren)) {
                    continue;
                }

                if(parentBom.getApsWorkOrder().getWorkChain().equals("WL")){
                    continue;
                }


                for (ApsWorkOrderTemp apsBom : apsBomChildren) {
                    apsBom.setPid(parentBom.getId());
                }
                temp.addAll(apsBomChildren);

            }

            parentBoms = temp;
            if(CollUtil.isNotEmpty(temp)){
                for (ApsWorkOrderTemp apsWorkOrderTemp : temp) {
                    apsWorkOrderTemp.setId(workOrderId++);
                }
            }
        }

        apsWorkOrderTempList.removeIf(e -> e.getId() == null);
        orderCache.setApsWorkOrderTempList(apsWorkOrderTempList);
        orderCache.setApsWorkOrderTempIdMap(orderCache.getApsWorkOrderTempList().stream().collect(Collectors.toMap(ApsWorkOrderTemp::getId, Function.identity())));
        orderCache.setApsWorkOrderTempPidMap(orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(ApsWorkOrderTemp::getPid, Collectors.toList())));

        // 取出倒排表数据
        List<ReverseDetail> reverseDetails = reverseDetailMapper.lambdaQuery().in(ReverseDetail::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        Map<String, ReverseDetail> collect1 = reverseDetails.stream().collect(Collectors.toMap(e -> e.getOrderId() + ":" + e.getBomId() + ":" + e.getPhaseId(), Function.identity(), (e1, e2) -> e1.getReverseEndTime().isBefore(e2.getReverseEndTime()) ? e1 : e2));
        reverseDetails = collect1.values().stream().sorted(Comparator.comparing(ReverseDetail::getReverseEndTime).thenComparing(ReverseDetail::getPhaseId)).collect(Collectors.toList());
        Map<Integer, List<ReverseDetail>> reverseDetailIdMap = reverseDetails.stream().collect(Collectors.groupingBy(ReverseDetail::getOrderId));
        Map<Integer, Map<Integer, ReverseDetail>> collect = reverseDetails.stream().collect(Collectors.groupingBy(ReverseDetail::getOrderId, Collectors.toMap(ReverseDetail::getPhaseId, Function.identity())));

        orderCache.setReverseDetailList(reverseDetails);
        orderCache.setReverseDetailOrderIdMap(reverseDetailIdMap);
        orderCache.setReverseDetailOrderIdPhaseIdMap(collect);

        // 构建 ApsWorkDetail 缓存对象
        Map<Integer, List<ApsWorkOrderTemp>> apsWorkOrderTempBomIdMap = apsWorkOrderTempList.stream().collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getBomId()));

        List<ApsWorkDetailTemp> apsWorkDetailTempList = new ArrayList<>();
        for (int i = 0; i < reverseDetails.size(); i++) {
            ReverseDetail e = reverseDetails.get(i);

            ApsWorkDetail apsWorkDetail = new ApsWorkDetail();
            apsWorkDetail.setOrderId(e.getOrderId());

            OrderPhase orderPhase = orderPhaseIdMap.get(e.getPhaseId());

            if(factoryCache.getIgnorePhaseCode().contains(orderPhase.getPhaseCode())){
                continue;
            }

            apsWorkDetail.setPhaseId(orderPhase.getId());
            apsWorkDetail.setWorkTime(orderPhase.getWorkTime());

            apsWorkDetail.setPhaseSeq(orderPhase.getPhaseSeq());
            apsWorkDetail.setPhaseCode(orderPhase.getPhaseCode());
            apsWorkDetail.setPhaseName(orderPhase.getPhaseName());
            apsWorkDetail.setPhaseCode(orderPhase.getPhaseCode());
            apsWorkDetail.setMaterNo(orderPhase.getMaterNo());
            apsWorkDetail.setMaterName(orderPhase.getMaterName());
            apsWorkDetail.setGroupCode(orderPhase.getWorkGroupNumber());
            apsWorkDetail.setOrderType(orderCache.getOrderIdMap().get(orderPhase.getOrderId()).getOrderType());

            // 从倒排表里取
            apsWorkDetail.setPartCount(orderCache.getOrderBomIdMap().get(e.getBomId()).getPartCount());
            apsWorkDetail.setGroupId(e.getGroupId());
            apsWorkDetail.setProcessCount(new BigDecimal(0));
            apsWorkDetail.setFinishCount(new BigDecimal(0));
            apsWorkDetail.setStatus(1);
            apsWorkDetail.setStationGroupId(e.getStationGroupId());

            apsWorkDetail.setDetailSeq(i + 1);
            apsWorkDetail.setReverseDetailId(e.getId());
            apsWorkDetail.setType(2);


            List<ApsWorkOrderTemp> apsWorkOrders = apsWorkOrderTempBomIdMap.get(orderPhase.getBomId());

            for (int i1 = 0; i1 < apsWorkOrders.size(); i1++) {
                ApsWorkOrderTemp apsWorkOrder = apsWorkOrders.get(i1);
                apsWorkDetail.setPlmId(apsWorkOrder.getApsWorkOrder().getPlmId()); // 注意，此处应该挪上面

                ApsWorkDetail awd = new ApsWorkDetail();
                BeanUtils.copyProperties(apsWorkDetail, awd);

                awd.setApsOrderId(apsWorkOrder.getApsWorkOrder().getApsOrderId());
                awd.setApsWorkOrderId(apsWorkOrder.getId());
                awd.setApsWorkOrderPid(apsWorkOrder.getPid());
                awd.setTotalCount(apsWorkOrder.getApsWorkOrder().getOrderCount());


                // 再计算转运数量
                List<Station> stationList = factoryCache.getMasterStationMap().get(e.getGroupCode());
                if(CollUtil.isEmpty(stationList)){
                    throw SyExceptionUtils.e("{}没有工位", e.getGroupCode());
                }
                Integer smallTransfer = stationList.get(0).getSmallTransfer();
                if (smallTransfer == null || smallTransfer <= 0) {
                    ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
                    temp.setApsWorkOrderTemp(apsWorkOrder);
                    temp.setApsWorkDetail(awd);
                    temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
                    apsWorkDetailTempList.add(temp);
                    continue;
                }

                int div = apsWorkOrder.getApsWorkOrder().getOrderCount().divide(new BigDecimal(smallTransfer), 0, RoundingMode.DOWN).intValue();

                BigDecimal subtract = apsWorkOrder.getApsWorkOrder().getOrderCount().subtract(new BigDecimal(smallTransfer).multiply(new BigDecimal(div)));

                for (int i2 = 0; i2 < div; i2++) {
                    ApsWorkDetail awd1 = MkBeanUtils.copyProperties(awd, ApsWorkDetail.class);
                    awd1.setTotalCount(new BigDecimal(smallTransfer));

                    ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
                    temp.setApsWorkOrderTemp(apsWorkOrder);
                    temp.setApsWorkDetail(awd1);
                    temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
                    apsWorkDetailTempList.add(temp);
                }

                if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                    ApsWorkDetail awd1 = MkBeanUtils.copyProperties(awd, ApsWorkDetail.class);
                    awd1.setTotalCount(subtract);

                    ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
                    temp.setApsWorkOrderTemp(apsWorkOrder);
                    temp.setApsWorkDetail(awd1);
                    temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
                    apsWorkDetailTempList.add(temp);
                }

            }

        }

        int workDetailId = 1;
        for (ApsWorkDetailTemp apsWorkDetailTemp : apsWorkDetailTempList) {
            apsWorkDetailTemp.setId(workDetailId++);
        }

        List<ApsTask> tasks = apsWorkDetailTempList.stream()
                .map(e -> {
                    ApsTask t = new ApsTask(e.getApsWorkDetail());
                    t.setApsWorkOrderTemp(e.getApsWorkOrderTemp());
                    t.setApsWorkDetailTemp(e);
                    t.setApsWorkOrder(e.getApsWorkOrder());
                    t.setId(e.getApsWorkDetail().getId());
                    t.setConsumerStatus(1);
                    t.setConsumerCount(new BigDecimal(0));
                    return t;
                })
                .sorted(Comparator.comparing(t -> t.getApsWorkDetail().getDetailSeq()))
                .collect(Collectors.toList());
        orderCache.setTaskList(tasks);


        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = tasks.stream().collect(Collectors.groupingBy( e-> e.getApsWorkOrderTemp().getId(), Collectors.groupingBy(ApsTask::getPhaseSeq)));
        orderCache.setWorkOrderIdPhaseSeqMap(workOrderIdPhaseSeqMap);

        Map<Integer, List<ApsTask>> workOrderPidMap = tasks.stream().filter(e -> e.getApsWorkOrderPid() != null).collect(Collectors.groupingBy(ApsTask::getApsWorkOrderPid));
        orderCache.setWorkOrderPidMap(workOrderPidMap);

        for (Order order : orderCache.getOrderList()) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
        }

        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
            apsOrder.setPlanStartDateTime(null);
            apsOrder.setPlanEndDateTime(null);
        }

    }

    public void modifyBatch(ApsBatch apsBatch, ApsSchedulingBatchReqVo reqVo) {
        LocalDateTime now = LocalDateTime.now();
        apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        apsBatch.setSchedulingDateTime(now);
        apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
    }

    public ApsBatch genBatch(ApsSchedulingBatchReqVo reqVo) {
        LocalDateTime now = LocalDateTime.now();
        ApsBatch apsBatch = new ApsBatch();
        apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
        apsBatch.setSchedulingDateTime(now);
        apsBatch.setStatus(1);
        return apsBatch;
    }

    public void unlock() {
        stringRedisTemplate.delete(ApsConstant.APS_SCHEDULING_LOCK);
    }


    @Transactional
    @SneakyThrows
    public List<HexagonPackagePush> converterAndSave(ApsNestHexagonReqVo reqVo) {

        Order order = orderMapper.selectById(reqVo.getOrderId());
        if (order.getPushStatus() != 1) {
            throw SyExceptionUtils.e("订单已推送，请查看推送详情");
        }
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getOrderId, order.getId()).list();
        if (CollUtil.isNotEmpty(pushPlanList) && pushPlanList.stream().anyMatch(e->e.getPushType()!=null)) {
            throw SyExceptionUtils.e("已有部分计划单独推送！");
        }
        Integer count = hexagonPackagePushMapper.lambdaQuery().eq(HexagonPackagePush::getOrderId, reqVo.getOrderId()).count();
        if(count > 0){
            throw SyExceptionUtils.e("订单已推送到海克斯康，如有异常请点击重新推送!");
        }

        List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery().eq(ApsOrder::getOrderId, reqVo.getOrderId()).list();

        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.lambdaQuery().eq(ApsWorkOrder::getOrderId, reqVo.getOrderId()).list();

        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().eq(OrderPhase::getOrderId, reqVo.getOrderId()).list();
        Map<Integer, List<OrderPhase>> orderPhaseBomIdMap = orderPhaseList.stream().collect(Collectors.groupingBy(OrderPhase::getBomId));

        // 转换对象
        List<HexagonPackagePush> packagePushList = converterHexagonPackagePushList(reqVo, order, apsOrderList, apsWorkOrderList, orderPhaseBomIdMap);

        for (HexagonPackagePush hexagonPackagePush : packagePushList) {
            hexagonPackagePushMapper.insert(hexagonPackagePush);
        }

        order.setPushStatus(2);
        order.setPushType(1);
        orderMapper.updateById(order);

        // 数据准备
        BaseIdReqVo idVo = new BaseIdReqVo();
        idVo.setId(order.getId());
        sinoCamService.pushMesMK(idVo);

        return packagePushList;

    }

    @SneakyThrows
    public List<HexagonPackagePush> converterHexagonPackagePushList(ApsNestHexagonReqVo reqVo, Order o, List<ApsOrder> apsOrderList, List<ApsWorkOrder> apsWorkOrderList, Map<Integer, List<OrderPhase>> orderPhaseBomIdMap) {

        XmlMapper xmlMapper = new XmlMapper();
//        xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);  // for Pretty print or formatting
        xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
        xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        xmlMapper.findAndRegisterModules();


        Map<String, Integer> params = new HashMap<>();
        params.put("Assembly", 1);
        params.put("Platepart", 2);
        params.put("Component", 3);

        apsOrderList.sort(Comparator.comparing(ApsOrder::getSeq));
//        apsOrderList = apsOrderList.subList(0, 1);
        Map<Integer, List<ApsWorkOrder>> pidMap = apsWorkOrderList.stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(ApsWorkOrder::getPid));
        List<ImportErpMapping> erpMappingList = importErpMappingMapper.lambdaQuery()
                .isNotNull(ImportErpMapping::getMesWorkPhase)
                .isNotNull(ImportErpMapping::getMesWorkCenter)
                .isNotNull(ImportErpMapping::getErpOpCode)
                .isNotNull(ImportErpMapping::getErpOp)
                .list();

        Map<String, Map<String, ImportErpMapping>> collect = erpMappingList.stream()
                .collect(
                        Collectors.groupingBy(ImportErpMapping::getMesWorkPhase,
                                Collectors.toMap(ImportErpMapping::getMesWorkCenter, Function.identity(), (e1, e2) ->
                                        e1.getErpOp().compareTo(e2.getErpOp()) > 0? e1 : e2)
                        )
                );


        List<HexagonPackagePush> rootList = new ArrayList<>();
        int dateIndex = 0;
        for (ApsOrder apsOrder : apsOrderList) {
            MesOrderRootReqDto root = new MesOrderRootReqDto();
            root.setSender("ERP");
            root.setTarget("SPx");
            root.setMsgSegNo(UUID.fastUUID().toString());
            root.setVersion("1.0");
            root.setDateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            root.setAction("BOM");
//            root.setMsgSegNo("9c874a9e-2eac-4530-a338-9b653636bdaa");
//            root.setDateTime("2024-12-23 12:03:15");

            MesOrderDataReqDto data = new MesOrderDataReqDto();
            root.setData(data);
            MesOrderDataCustomerDataReqDto customerData = new MesOrderDataCustomerDataReqDto();
            customerData.setName(reqVo.getCustName());
            customerData.setCustomerNumber(reqVo.getCustCode());
            customerData.setOffsetX1("0");
            customerData.setOffsetY("90.000");
            customerData.setRotation("0");

            MesOrderDataCustomerOrderDataReqDto customerOrderData = new MesOrderDataCustomerOrderDataReqDto();
            customerOrderData.setOrderName(reqVo.getMesOrderCode());
            customerOrderData.setInfo(o.getMaterName());
            String pkgCode = null;
            if(CollUtil.isNotEmpty(reqVo.getItem()) && dateIndex < reqVo.getItem().size()){
                if(reqVo.getItem().get(dateIndex).getDeliveryDate() != null){
                    customerOrderData.setDueDate(reqVo.getItem().get(dateIndex).getDeliveryDate().toString());
                } else {
                    customerOrderData.setDueDate(o.getDeliveryDateTime().toLocalDate().toString());
                }
                if(reqVo.getItem().get(dateIndex).getPkgCode() != null){
                    pkgCode = reqVo.getItem().get(dateIndex).getPkgCode();
                } else {
                    pkgCode = PkgUtils.gen(apsOrder.getSeq());
                }
            } else {
                customerOrderData.setDueDate(o.getDeliveryDateTime().toLocalDate().toString());
                pkgCode = PkgUtils.gen(apsOrder.getSeq());
            }
            dateIndex++;



            customerOrderData.setInfo(o.getMaterName());

            data.setCustomerOrderData(customerOrderData);
            data.setCustomerData(customerData);
            List<MesOrderDataAssemblyReqDto> assemblyList = new ArrayList<>();
            data.setAssembly(assemblyList);

            MesOrderDataAssemblyReqDto c = apsWorkOrderToAss(o, apsOrder, pkgCode);
            assemblyList.add(c);

            Optional<ApsWorkOrder> first = apsWorkOrderList.stream().filter(e -> e.getPid() == null && e.getApsOrderId().equals(apsOrder.getId())).findFirst();
            if (!first.isPresent()) {
                continue;
            }


            ApsWorkOrder top = first.get();
//            List<MesOrderDataAssemblyReqDto> parentAss = new ArrayList<>();
//            parentAss.add(c);

            Map<Integer, MesOrderDataAssemblyReqDto> hashMap = new HashMap<>();
            List<ApsWorkOrder> parent = new ArrayList<>();
            if(o.getSerialCode().equals(top.getPlmId())){
                List<ApsWorkOrder> apsWorkOrder = apsWorkOrderList.stream().filter(e -> e.getPid() != null && e.getPid().equals(top.getId())).collect(Collectors.toList());
                for (ApsWorkOrder workOrder : apsWorkOrder) {
                    workOrder.setAssemblyPath("/" + workOrder.getPlmId());
                }
                parent.addAll(apsWorkOrder);
            } else {
                parent.add(top);
                top.setAssemblyPath("/" + top.getPlmId());
            }
            while(true){

                List<ApsWorkOrder> temp = new ArrayList<>();
                for (ApsWorkOrder assembly : parent) {
                    MesOrderDataAssemblyReqDto c1 = null;
                    if(assembly.getMaterType().equals("Assembly")){
                        c1 = apsWorkOrderToAss(o, apsOrder, assembly);
                        hashMap.put(assembly.getId(), c1);
                        if (assembly.getPid() == null || hashMap.get(assembly.getPid()) == null) {
                            if (c.getAssembly() == null) {
                                c.setAssembly(new ArrayList<>());
                            }
                            c.getAssembly().add(c1);
                        } else {
                            if (hashMap.get(assembly.getPid()).getAssembly() == null) {
                                hashMap.get(assembly.getPid()).setAssembly(new ArrayList<>());
                            }
                            hashMap.get(assembly.getPid()).getAssembly().add(c1);
                        }

                        List<ApsWorkOrder> apsWorkOrders = pidMap.get(assembly.getId());
                        if (CollUtil.isNotEmpty(apsWorkOrders)) {
                            for (ApsWorkOrder apsWorkOrder : apsWorkOrders) {
                                apsWorkOrder.setAssemblyPath(assembly.getAssemblyPath() + "/" + apsWorkOrder.getPlmId());
                            }
                            temp.addAll(apsWorkOrders);
                        }

                        List<OrderPhase> phaseList = orderPhaseBomIdMap.get(assembly.getBomId());
                        List<MesOrderDataWorkDetailReqDto> list = apsWorkDetailToWorkDetail( assembly, phaseList,collect);
                        c1.setWorkDetails(list);
                    } else if(assembly.getMaterType().equals("Platepart")){
                        MesOrderDataPlatepartReqDto platepart = apsWorkOrderToPlatePart(o, assembly);
                        MesOrderDataAssemblyReqDto pp = hashMap.get(assembly.getPid());
                        if(pp.getPlatepart() == null){
                            pp.setPlatepart(new ArrayList<>());
                        }
                        pp.getPlatepart().add(platepart);
                        List<OrderPhase> phaseList = orderPhaseBomIdMap.get(assembly.getBomId());
                        List<MesOrderDataWorkDetailReqDto> list = apsWorkDetailToWorkDetail( assembly, phaseList,collect);
                        platepart.setWorkDetails(list);
                    } else if(assembly.getMaterType().equals("Component")){
                        MesOrderDataComponentReqDto component = apsWorkOrderToComponent(o, assembly);
                        MesOrderDataAssemblyReqDto pp = hashMap.get(assembly.getPid());
                        if(pp.getComponent() == null){
                            pp.setComponent(new ArrayList<>());
                        }
                        pp.getComponent().add(component);
                        List<MesOrderDataWorkDetailReqDto> list = new ArrayList<>();
                        MesOrderDataWorkDetailReqDto mesOrderDataWorkDetailReqDto = new MesOrderDataWorkDetailReqDto();
                        mesOrderDataWorkDetailReqDto.setId(1);
                        mesOrderDataWorkDetailReqDto.setWorkTime("0");
                        mesOrderDataWorkDetailReqDto.setWorkPhase("WL");
                        mesOrderDataWorkDetailReqDto.setMesWorkCenter("2-4_LLGW_01");
                        list.add(mesOrderDataWorkDetailReqDto);
                        component.setWorkDetails(list);
                    }
                }
                if(CollUtil.isEmpty(temp)){
                    break;
                }

                parent = temp;
                parent.sort((e1, e2) ->{
                    int i = params.get(e1.getMaterType()).compareTo(params.get(e1.getMaterType()));
                    if(i != 0){
                        return i;
                    }

                    return e1.getPlmId().compareTo(e2.getPlmId());
                });


            }

            HexagonPackagePush hexagonPackagePush = new HexagonPackagePush();
            hexagonPackagePush.setOrderId(reqVo.getOrderId());
            hexagonPackagePush.setApsOrderId(apsOrder.getId());
            hexagonPackagePush.setStatus(1);
            hexagonPackagePush.setPackageCode(c.getAssemblyName());


            String filePath = "/home/storage/hexagon/push/%s/%s.txt";
            String yyyyMM = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
            String path = String.format(filePath, yyyyMM, IdUtil.fastSimpleUUID());

            FileUtils.writeStringToFile(new File(path), xmlMapper.writeValueAsString(root), "UTF-8");

            hexagonPackagePush.setRequestPath(path);
            hexagonPackagePush.setCustName(reqVo.getCustName());
            hexagonPackagePush.setCustCode(reqVo.getCustCode());
            hexagonPackagePush.setMesOrderCode(reqVo.getMesOrderCode());
            hexagonPackagePush.setMesOrderId(reqVo.getMesOrderId());
            hexagonPackagePush.setEndDate(LocalDate.parse(customerOrderData.getDueDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));


            rootList.add(hexagonPackagePush);

        }
        return rootList;
    }

    public MesOrderDataComponentReqDto apsWorkOrderToComponent(Order o, ApsWorkOrder apsWorkOrder) {
        MesOrderDataComponentReqDto component = new MesOrderDataComponentReqDto();
        component.setName(apsWorkOrder.getPlmId());
        component.setWorkChain(apsWorkOrder.getWorkChain());
        if(apsWorkOrder.getMaterWeight() != null){
            component.setWeight(apsWorkOrder.getMaterWeight().toPlainString());
        }
        component.setPlmId(apsWorkOrder.getPlmId());
        component.setDrawing(apsWorkOrder.getDrawing());
        if(!StringUtils.hasText(component.getDrawing())){
            component.setDrawing(component.getPlmId());
        }
        component.setErpId(apsWorkOrder.getErpCode());
        component.setCount(String.valueOf(apsWorkOrder.getPartCount().intValue()));
        component.setInfo(apsWorkOrder.getMaterName());
        component.setConstructNo(o.getConstructNo());
        component.setConstructOrderNo(apsWorkOrder.getWorkOrderCode());
        component.setAssemblyPath(apsWorkOrder.getAssemblyPath());
        return component;
    }

    public MesOrderDataPlatepartReqDto apsWorkOrderToPlatePart(Order o, ApsWorkOrder apsWorkOrder) {
        MesOrderDataPlatepartReqDto platepart = new MesOrderDataPlatepartReqDto();
        platepart.setName(apsWorkOrder.getPlmId());
        platepart.setWorkChain(apsWorkOrder.getWorkChain());
        platepart.setType("Important");
        platepart.setInfo(apsWorkOrder.getMaterHigh().toString());
        platepart.setWeight(apsWorkOrder.getMaterWeight().toPlainString());
        platepart.setDrawing(apsWorkOrder.getDrawing());
        platepart.setPlmId(apsWorkOrder.getPlmId());
        if(!StringUtils.hasText(platepart.getDrawing())){
            platepart.setDrawing(platepart.getPlmId());
        }
        platepart.setErpId(apsWorkOrder.getErpCode());
        platepart.setCount(String.valueOf(apsWorkOrder.getPartCount().intValue()));
        platepart.setInfo(apsWorkOrder.getMaterName());
        platepart.setMaterial(apsWorkOrder.getTexture());
        platepart.setConstructNo(o.getConstructNo());
        platepart.setConstructOrderNo(apsWorkOrder.getWorkOrderCode());
        platepart.setAssemblyPath(apsWorkOrder.getAssemblyPath());
        platepart.setThickness(apsWorkOrder.getMaterHigh().toString());
        return platepart;
    }

    public List<MesOrderDataWorkDetailReqDto> apsWorkDetailToWorkDetail(ApsWorkOrder assembly, List<OrderPhase> orderPhaseList, Map<String, Map<String, ImportErpMapping>> collect) {
        if (CollUtil.isEmpty(orderPhaseList)){
            return null;
        }
        List<MesOrderDataWorkDetailReqDto> list = new ArrayList<>();
        orderPhaseList.removeIf(e-> e.getPhaseCode().equals(WorkshopProp.LL_PHASE_CODE) || e.getPhaseCode().equals(WorkshopProp.KJ_PHASE_CODE));
        orderPhaseList.sort(Comparator.comparing(OrderPhase::getPhaseSeq));
        for (OrderPhase orderPhase : orderPhaseList) {
            MesOrderDataWorkDetailReqDto workDetail = new MesOrderDataWorkDetailReqDto();
            workDetail.setId(list.size() + 1);
            workDetail.setWorkTime(new BigDecimal(orderPhase.getOriWorkTime()).divide(new BigDecimal("60"), 4, RoundingMode.HALF_UP).toPlainString());
            workDetail.setWorkPhase(orderPhase.getPhaseCode());
            workDetail.setMesWorkCenter(orderPhase.getWorkGroupNumber());
            workDetail.setErpSeq(workDetail.getId());
            workDetail.setErpOp(orderPhase.getPhaseCode());
            workDetail.setErpOpCode(orderPhase.getWorkGroupNumber());
            list.add(workDetail);
        }

        return list;
    }

    public MesOrderDataAssemblyReqDto apsWorkOrderToAss(Order o, ApsOrder apsOrder, ApsWorkOrder apsWorkOrder) {
        MesOrderDataAssemblyReqDto assembly = new MesOrderDataAssemblyReqDto();
        assembly.setAssemblyName(apsWorkOrder.getPlmId());
        assembly.setWorkChain(apsWorkOrder.getWorkChain());
        assembly.setPartCount(String.valueOf(apsWorkOrder.getPartCount().intValue()));
        assembly.setInfo(apsWorkOrder.getMaterName());
        assembly.setDrawing(apsWorkOrder.getDrawing());
        assembly.setPlmId(apsWorkOrder.getPlmId());
        if(!StringUtils.hasText(assembly.getDrawing())){
            assembly.setDrawing(assembly.getPlmId());
        }
        assembly.setWeight(apsWorkOrder.getMaterWeight());
        assembly.setErpId(apsWorkOrder.getErpCode());
        assembly.setConstructNo(o.getConstructNo());
        assembly.setConstructOrderNo(apsWorkOrder.getWorkOrderCode());
        assembly.setAssemblyPath(apsWorkOrder.getAssemblyPath().replaceFirst("/Z188-LS_170", ""));

        return assembly;
    }

    public MesOrderDataAssemblyReqDto apsWorkOrderToAss(Order o, ApsOrder apsOrder, String pkgCode) {
        MesOrderDataAssemblyReqDto assembly = new MesOrderDataAssemblyReqDto();
        assembly.setAssemblyName(pkgCode);
        assembly.setWorkChain("");
        assembly.setPartCount(String.valueOf(apsOrder.getOrderQty()));
        assembly.setInfo("Workpackage");
        assembly.setErpId("");
        assembly.setConstructNo("");
        assembly.setConstructOrderNo("");

        return assembly;
    }

    public BaseListResVo<HexagonPushListResVo> hexagonPushList(BaseIdReqVo reqVo) {
        List<HexagonPackagePush> list = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, reqVo.getId())
                .orderByAsc(HexagonPackagePush::getApsOrderId)
                .list();
        BaseListResVo<HexagonPushListResVo> hexagonPushListResVoBaseListResVo = BaseListResVo.of(list, HexagonPushListResVo.class);
        for (HexagonPushListResVo datum : hexagonPushListResVoBaseListResVo.getData()) {
            Order order = orderMapper.selectById(datum.getOrderId());
            datum.setMaterCode(order.getMaterCode());
            datum.setMaterName(order.getMaterName());
            datum.setSerialCode(order.getSerialCode());
        }

        return hexagonPushListResVoBaseListResVo;
    }

    @SneakyThrows
    public HexagonPushDetailResVo hexagonPushDetail(BaseIdReqVo reqVo) {
        HexagonPackagePush hexagonPackagePush = hexagonPackagePushMapper.selectById(reqVo.getId());
        HexagonPushDetailResVo resVo = new HexagonPushDetailResVo();
        if(hexagonPackagePush.getRequestPath() != null){
            resVo.setRequestBody(FileUtils.readFileToString(new File(hexagonPackagePush.getRequestPath()), "UTF-8"));
        }
        if(hexagonPackagePush.getResponsePath() != null){
            resVo.setResponseBody(FileUtils.readFileToString(new File(hexagonPackagePush.getResponsePath()), "UTF-8"));
        }
        return resVo;
    }

    @SneakyThrows
//    @Transactional // 不要加事务，否则会导致在同一事务中
    public void sendToMes(HexagonPackagePush packagePushList) {
        HexagonPackagePush p = new HexagonPackagePush();
        p.setId(packagePushList.getId());
        p.setStatus(2);
        p.setErrorMsg("");
        p.setResponsePath(null);

        hexagonPackagePushMapper.updateById(p);
        long start = System.currentTimeMillis();

        String requestBody = FileUtils.readFileToString(new File(packagePushList.getRequestPath()), "UTF-8");

        log.info("MES-订单导入-请求：{}",requestBody);
//        String body = HttpUtil.createPost("http://172.31.3.177/SPxSSC_API/api/v1.0/bridge")
//                .contentType(MediaType.APPLICATION_XML_VALUE)
//                .body(requestBody)
//                .execute()
//                .body();



        try (HttpResponse execute = HttpUtil.createPost(mesUrlOrder)
                .contentType("application/xml")
                .header("Accept-Encoding", "gzip, deflate, br")
                .header("Accept", "*/*")
                .body(requestBody, "application/xml")
                .execute()){

            String body = execute.body();

            log.info("MES-订单导入-响应：{}",body);

            String path =FileStorageUtils.getFilePath(FileStorageUtils.NEST_HEXAGON_TYPE);

            FileUtils.writeStringToFile(new File(path), body,"UTF-8");
            p.setResponsePath(path);


            XmlMapper xmlMapper = new XmlMapper();
            JsonNode jsonNode = xmlMapper.readTree(body);
            if(!jsonNode.get("StatusCode").asText().equals("200")){
                p.setStatus(4);
                if(jsonNode.get("ErrorMessage") != null && jsonNode.get("ErrorMessage").asText().length() > 100){
                    p.setErrorMsg(jsonNode.get("ErrorMessage").asText().substring(0, 100));
                } else {
                    p.setErrorMsg(jsonNode.get("ErrorMessage").asText());
                }
            }else {
                p.setStatus(3);
                p.setWorkTime(System.currentTimeMillis() - start);
            }
        } catch (Exception e) {
            e.printStackTrace();
            p.setStatus(4);
            p.setWorkTime(System.currentTimeMillis() - start);
        } finally {
            hexagonPackagePushMapper.updateById(p);
        }


        // 如果有推送中的，就为推送中
        Order order = orderMapper.selectById(packagePushList.getOrderId());

        Integer count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, packagePushList.getOrderId())
                .in(HexagonPackagePush::getStatus, 1,2)
                .count();
        if (count > 0) {
            order.setPushStatus(2);
            orderMapper.updateById(order);
            return ;
        }



        count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, packagePushList.getOrderId())
                .ne(HexagonPackagePush::getStatus, 3)
                .count();
        if (count > 0) {
            order.setPushStatus(4);
            orderMapper.updateById(order);
        } else {
            order.setPushStatus(3);
            orderMapper.updateById(order);
        }

    }

    public HexagonPackagePush getByHexagonPushId(Integer id) {
        return hexagonPackagePushMapper.selectById(id);
    }

    @SneakyThrows
    public HexagonOrderListResVo<HexagonOrderListItemResVo> hexagonOrderList(HexagonOrderListReqVo reqVo) {
        List<HexagonOrderListItemResVo> list = apsMesFeign.orderList();
        HexagonOrderListResVo<HexagonOrderListItemResVo> resVo = HexagonOrderListResVo.of(list, HexagonOrderListItemResVo.class);

        if(reqVo.getOrderId() == null){
            resVo.setErrorMsg("没有传订单ID，无法自动匹配");
            return resVo;
        }

        Order order = orderMapper.selectById(reqVo.getOrderId());
        if(order == null || order.getOrderType() == null){
            resVo.setErrorMsg("没有找到该订单或者订单类型");
            return resVo;
        }
        if(!order.getOrderType().equals(1)){
            resVo.setErrorMsg("订单类型不是ERP，不能自动匹配");
            return resVo;
        }

        String newOrderCode = genNewOrderCode(order);
        if(newOrderCode == null){
            resVo.setErrorMsg("不是三大件加侧板，无法自动匹配。");
            return resVo;
        }

        Optional<HexagonOrderListItemResVo> mesOrderCode = list.stream().filter(e -> e.getMesOrderCode().endsWith(newOrderCode)).findFirst();
        if(mesOrderCode.isPresent()){
            resVo.setSelectVal(mesOrderCode.get().getMesOrderId());
        } else {
            resVo.setErrorMsg("没有找到对应的MES订单号，请检查是否正确");
        }

        return resVo;
    }

    public static String genNewOrderCode(Order order) {
        String orderCode = order.getConstructNo();

        if (order.getMaterName().startsWith("顶梁") && order.getMaterName().endsWith("拼")) {
            orderCode = orderCode + "D";
            return orderCode;
        }
        if (order.getMaterName().startsWith("底座") && order.getMaterName().endsWith("拼")) {
            orderCode = orderCode + "Z";
            return orderCode;
        }

        if (order.getMaterName().startsWith("掩护梁") && order.getMaterName().endsWith("拼")) {
            orderCode = orderCode + "Y";
            return orderCode;
        }

        if (order.getMaterName().equals("侧板")) {
            orderCode = orderCode + "C";
            return orderCode;
        }

        if (order.getMaterName().equals("连杆")) {
            orderCode = orderCode + "L";
            return orderCode;
        }


        if (order.getMaterName().equals("推杆")) {
            orderCode = orderCode + "T";
            return orderCode;
        }


        if (order.getMaterName().equals("护帮")) {
            orderCode = orderCode + "B";
            return orderCode;
        }

        return null;
    }

    public BaseListResVo<HexagonPreviewPackageResVo> previewHexagonPackage(BaseIdReqVo reqVo) {
        List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery()
               .eq(ApsOrder::getOrderId, reqVo.getId())
               .list();

        return new BaseListResVo<>(apsOrderList.stream()
                .sorted(Comparator.comparing(ApsOrder::getSeq))
                .map(e -> {
                    HexagonPreviewPackageResVo resVo = new HexagonPreviewPackageResVo();
                    resVo.setId(e.getId());
                    resVo.setPkgCode(PkgUtils.gen(e.getSeq()));
                    resVo.setDeliveryDate(e.getDeliveryDate());
                    resVo.setOrderQty(e.getOrderQty());
                    return resVo;
                })
                .collect(Collectors.toList()));

    }

    @Async("taskExecutor")
    public void sendToMesAll(List<HexagonPackagePush> packagePushList) {
        for (HexagonPackagePush hexagonPackagePush : packagePushList) {
            sendToMes(hexagonPackagePush);
        }
    }

    public List<Order> listOrder(ApsSchedulingBatchReqVo reqVo) {
        List<Order> orderList = orderMapper.selectBatchIds(reqVo.getOrderIdList());
        return orderList;
    }


    @Transactional
    public void reverseScheduling(ApsReverseSchedulingReqVo reqVo) {
//        List<Order> orderList = orderMapper.lambdaQuery()
//               .in(Order::getId, reqVo.getOrderIds())
//               .list();
    }

    @Transactional
    public void valid(ApsNestHexagonReqVo reqVo) {

        if(CollUtil.isEmpty(reqVo.getItem())){
            return ;
        }

        List<String> pkgCode = reqVo.getItem().stream().map(ApsNestHexagonItemReqVo::getPkgCode).collect(Collectors.toList());
        List<String> disPkgCode = pkgCode.stream().distinct().collect(Collectors.toList());
        if(pkgCode.size() > disPkgCode.size()){
            throw SyExceptionUtils.e("存在重复的包，请修改包名不重复");
        }

        Integer count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getMesOrderCode, reqVo.getMesOrderCode())
                .in(HexagonPackagePush::getPackageCode, pkgCode)
                .count();

        if(count > 0){
            throw SyExceptionUtils.e("MES的同一个包不能推送两次，请检查MES的包下是否有数据");
        }


    }
}
